#pragma once

#include <vector>
#include <string>
#include <Common/Elf.h>
#include <boost/noncopyable.hpp>


namespace DB
{

/** Allow to quickly find symbol name from address.
  * Used as a replacement for "dladdr" function which is extremely slow.
  * It works better than "dladdr" because it also allows to search private symbols, that are not participated in shared linking.
  */
class SymbolIndex : private boost::noncopyable
{
protected:
    SymbolIndex() { load(); }

public:
    static const SymbolIndex & instance();

    struct Symbol
    {
        /// Here addresses are relative to objects.
        const void * offset_begin;
        const void * offset_end;
        const char * name;
    };

    struct Object
    {
        /// Here addresses are absolute virtual memory addresses.
        const void * address_begin;
        const void * address_end;
        std::string name;
        std::shared_ptr<Elf> elf;
    };

    const Symbol * findSymbol(const void * offset) const;
    const Object * findObject(const void * address) const;
    const Object * thisObject() const;

    const std::vector<Symbol> & symbols() const { return data.symbols; }
    const std::vector<Object> & objects() const { return data.objects; }

    /// The BuildID that is generated by compiler.
    String getBuildID() const { return data.self_build_id; }
    String getBuildIDHex() const;

    struct Data
    {
        std::vector<Symbol> symbols;
        std::vector<Object> objects;
        /// BuildID from the Object corresponding to main executable (as opposed to dynamic libraries).
        String self_build_id;
    };
private:
    Data data;

    void load();
};

}
